# coding=UTF-8
import os
import random
from brain_model import Brain
from block_model import Block
from core_model import Core
from common_model import Common
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import cv2
import threading
import time
import serial

# 描述世界的类
class World:
	# 参数
	width = 50 # 宽度 50
	height = 50 # 高度 50
	soul_num = 10 # 灵魂数量 30
	move_span = 10 # 生移动间隔 10
	life_span = int(100 * move_span) # 生的寿命 1000
	put_span = int(20 * move_span) # 投放生的间隔 200
	statistic_span = 1000 # 统计信息衰减间隔（统计信息衰减以显示较新数据）
	cap_use_num = 1 # 摄像头编号
	cap_show_num = 0

	# 初始化世界
	def __init__(self):
		# 调试变量
		self.arrival_enable = 0 # 是否降临物质世界
		# 初始化世界中所有块
		block_list = []
		for i in range(World.height):
			for j in range(World.width):
				block_ = Block(0.92, i, j, self.world_grid_io)
				block_list.append(block_)
		self.block_list = block_list
		# 初始化神赐之种
		i = random.randint(0, World.height - 1)
		j = random.randint(0, World.width - 1)
		while self.block_list[i * World.width + j].type != Common.BLOCK_NONE:
			i = random.randint(0, World.height - 1)
			j = random.randint(0, World.width - 1)
		self.block_list[i * World.width + j].type = Common.BLOCK_SEED
		# 神赐之种坐标
		self.seed_i = i
		self.seed_j = j
		# 初始化时间
		self.time = 0
		# 魂，存放活得长久的生的拷贝
		self.soul_list = []
		# 神赐之脑
		self.brain_list = []
		self.brain_list.append(Brain(Common.BLOCK_dimension, Common.BLOCK_size, [], self.operator_grid_io)) # 提供全运算符 0
		self.brain_list.append(Brain(Common.BLOCK_dimension, Common.BLOCK_size, [], self.round_grid_io)) # 提供生周围视野 1
		self.brain_list.append(Brain(Common.BLOCK_dimension, Common.BLOCK_size, [], self.info_grid_io)) # 提供寿命、位置信息 2
		# self.brain_list.append(Brain(3, 8, [], self.base_ether_io)) # 0：中继，直接连接生与所有脑
		# self.brain_list.append(Brain(3, 9, [], self.round_ether_io)) # 1：提供生周围9*9视野
		# if self.arrival_enable:
		# 	self.brain_list.append(Brain(3, 8, [], self.motor_ether_io)) # 2：控制继电器
		# 	self.brain_list.append(Brain(3, 8, [], self.camera_ether_io)) # 3：读取摄像头画面
		# else:
		# 	self.brain_list.append(Brain(3, 8, [], self.base_ether_io))
		# 	self.brain_list.append(Brain(3, 8, [], self.base_ether_io))
		self.brain_user = 0 # 0为未使用，占用则指向使用者
		# 固定虚空连接
		World.set_connect(self.brain_list[0], self.brain_list[1], 20)
		World.set_connect(self.brain_list[0], self.brain_list[2], 20)
		World.set_connect(self.brain_list[1], self.brain_list[2], 20)
		# 可变虚空连接点位（每次生死亡需要更新）
		self.connect_list = [] # [[0: 起点块, 1: 终点块, 2: 起点位置, 3: 终点位置], ...] block_t指代生
		# 暂时只使用前三维后半块建立虚空连接
		connect_start_place = int(pow(Common.BLOCK_size, 3) / 2)
		connect_end_place = pow(Common.BLOCK_size, 3) - 1
		for i in range(20): # 生到周围环境神赐之脑的虚空连接
			start_block = 'block_t'
			end_block = self.brain_list[0]
			start_place = random.randint(connect_start_place, connect_end_place)
			end_place = random.randint(connect_start_place, connect_end_place)
			self.connect_list.append([start_block, end_block, start_place, end_place])
		for i in range(20): # 周围环境神赐之脑到生的虚空连接
			start_block = self.brain_list[0]
			end_block = 'block_t'
			start_place = random.randint(connect_start_place, connect_end_place)
			end_place = random.randint(connect_start_place, connect_end_place)
			self.connect_list.append([start_block, end_block, start_place, end_place])
		# 物质世界信息
		if self.arrival_enable:
			self.cap_use = cv2.VideoCapture(World.cap_use_num)
			self.cap_show = cv2.VideoCapture(World.cap_show_num)
		else:
			self.cap_use = 0
			self.cap_show = 0
		self.img_use = 0 # 生使用的摄像头画面
		self.img_show = 0 # 用于结果展示的摄像头画面
		self.motor_place = 0.0 # 用于补偿相机位置
		# 统计信息
		# 1. 统计死被移动的次数
		self.dead_move = 0 # 死被移动的次数
		# 3. 统计平均分
		self.score_all = 0 # 分数总和
		self.score_num = 0 # 被统计分数的生个数
		# 4. 统计平均寿命探测次数
		self.detect_age_all = 0 # 探查寿命次数
		# 5. 统计平均掠夺次数
		self.attack_all = 0 # 掠夺次数
		# 6. 统计横坐标探测次数
		self.detect_j_all = 0
		# 7. 统计纵坐标探测次数
		self.detect_i_all = 0
		# 8. 统计随机点探测次数
		self.detect_none_all = 0
		# 刻印
		self.max_scar_length = Common.BLOCK_size * Common.BLOCK_dimension # 最大刻印长度
		self.scar_func_type_num = 7 # 刻印功能数量
		self.scar_func_num = 4 * self.scar_func_type_num # 单长度刻印数量
		self.scar = [] # 刻印是三维列表，第一维是刻印长度，第二维是刻印功能，第三维存放刻印本身
		for i in range(self.max_scar_length):
			one_scar = []
			for j in range(self.scar_func_num):
				one_one_scar = []
				for k in range(i):
					one_one_scar.append(random.random() * 2.0 - 1.0) # 取值范围(-1, 1)
				one_scar.append(np.array(one_one_scar))
			self.scar.append(one_scar)
		# 统计刻印调用频率
		self.scar_active = [] # 二维列表，第一维是刻印长度，第二维是刻印功能
		for i in range(self.max_scar_length):
			one_scar_active = []
			for j in range(self.scar_func_num):
				one_scar_active.append(0.0)
			self.scar_active.append(one_scar_active)
		self.scar_active = np.array(self.scar_active)
		# 统计神赐之脑内的数据流向
		self.grid_io_log = [] # [[块, 类型, 起点坐标, 终点坐标], ...]
		# 统计各神赐之脑内部数据读取情况
		self.none_brain_num = 0 # 对照
		self.round_brain_num = 0 # 环境
		self.and_brain_num = 0 # 与运算
		self.and_brain_yes_num = 0 # 与运算返回正
		self.or_brain_num = 0 # 或运算
		self.or_brain_yes_num = 0 # 或运算返回正
		self.not_brain_num = 0 # 非运算
		self.not_brain_yes_num = 0  # 非运算返回正
		# 标记回路
		# 如果一条路径头尾相连，可称之为回路。如果一条回路在参数被改变，路径被打断后，依然会重复出现，可称之为自稳定回路
		# 如果自稳定回路，会在不同条件下走向不同的路径，可称之为可选择自稳定回路
		# 当可选择自稳定回路1做出选择后，需要由另一个可选择自稳定回路2探测额外的点位，并由回路2选择是否加强回路1的选择
		# 回路1与回路2构成的整体，可称为可学习回路
		# 如果可学习回路，可以不断尝试新选择，不断尝试新探测点位，便可不断衍生新可学习回路，此时可称之为自编程回路
		self.path = {} # 最高分块内存在的路径，{place * max_size + vector: time, ...}
		self.cycle = {} # 重复出现的路径
		self.path_span = 10 # 路径持续时间，即与多久之前的路径重复算是环
		self.cycle_span = self.path_span # 环持续时间，即多久之前的环会被绘制
		self.path_num = {} # 统计所有路径出现次数，{place * max_size + vector: [num, index], ...}
		# 构筑傀儡回路
		self.tool_cycle_all = 0 # 傀儡回路激活总数
		self.tool_cycle_num = 0 # 傀儡回路回答正确次数

	def read_img(self):
		# 读取生使用的摄像头画面
		ret, frame = self.cap_use.read() # 480, 640
		gray_img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
		size = self.brain_list[3].size # 设置画面大小为生读取摄像头画面脑的尺寸
		self.img_use = cv2.resize(gray_img, (size, size), interpolation = cv2.INTER_LANCZOS4) 
		# # 读取用于结果展示的摄像头画面
		# ret, frame = self.cap_show.read() # 480, 640
		# self.img_show = frame

	def set_motor(self, com, duration, direction):
		try:
			ser = serial.Serial(com, 9600)    # 打开串口
			write_len = ser.write(bytearray([0xA0, 0x01, 0x01, 0xA2])) # 打开继电器
			time.sleep(duration)
			write_len = ser.write(bytearray([0xA0, 0x01, 0x00, 0xA1])) # 关闭继电器
			ser.close()
			self.motor_place += duration * direction # 记录相机位置
		except:
			return

	# 建立虚空连接
	def set_connect(block_0, block_1, connect_num):
		# 暂时只使用前三维后半块建立虚空连接
		connect_start_place = int(pow(Common.BLOCK_size, 3) / 2)
		connect_end_place = pow(Common.BLOCK_size, 3) - 1
		for i in range(connect_num):
			# 建立block_0到block_1的虚空连接
			start_place = random.randint(connect_start_place, connect_end_place)
			end_place = random.randint(connect_start_place, connect_end_place)
			block_0.connect.append([start_place, block_1, end_place])
			# 建立block_1到block_0的虚空连接
			start_place = random.randint(connect_start_place, connect_end_place)
			end_place = random.randint(connect_start_place, connect_end_place)
			block_1.connect.append([start_place, block_0, end_place])

	# 初始化寿命，避免同死
	def init_time(self):
		for i in range(len(self.block_list)):
			self.block_list[i].time = random.randint(0, World.life_span)

	# 初始化核
	def init_core(self, live_num):
		# 新增核
		for t in range(live_num):
			for tt in range(100): # 尝试寻找不是死的块
				i = random.randint(0, World.height - 1)
				j = random.randint(0, World.width - 1)
				if self.block_list[i * World.width + j].type == Common.BLOCK_NONE:
					core_num = int(0.1 * pow(self.block_list[i * World.width + j].size, \
						           self.block_list[i * World.width + j].dimension))
					for k in range(core_num):
						core = Core(self.block_list[i * World.width + j])
					break
	# 挑选魂
	def pick(self):
		pick = random.randint(0, len(self.soul_list) - 1)
		# age_sum = sum(item.score for item in self.soul_list)
		# age_min = min(item.score for item in self.soul_list)
		# rand_num = random.randint(0, age_sum - age_min * len(self.soul_list))
		# pick = len(self.soul_list) - 2
		# for i in range(len(self.soul_list) - 1):
		# 	rand_num -= self.soul_list[i].score - age_min
		# 	if rand_num < 0:
		# 		pick = i
		# 		break
		return pick

	def to_direction(i, j, direction):
		t_i = i
		t_j = j
		# 0：左，1：上，2：右，3：下 
		if direction == 0:
			t_j -= 1
		if direction == 1:
			t_i -= 1
		if direction == 2:
			t_j += 1
		if direction == 3:
			t_i += 1
		return t_i, t_j

	# 时间流逝
	def tick_tock(self):
		self.time += 1
		self.grid_io_log = [] # 每次都清除数据
		# 读取摄像头数据
		if self.arrival_enable:
			thread = threading.Thread(target = self.read_img)
			thread.start()  # 启动线程
		# 核的行动
		for i in range(len(self.block_list)):
			if self.block_list[i].type != Common.BLOCK_LIVE:
				continue
			# 核的行走
			for j in range(len(self.block_list[i].core_list)):
				self.block_list[i].core_list[j].tick_tock(self)
		# 清理空核
		for i in range(len(self.block_list)):
			if self.block_list[i].type != Common.BLOCK_LIVE:
				continue
			self.block_list[i].clean()
		# 生的行动
		if self.time % World.move_span == 0:
			move = []
			for i in range(len(self.block_list)):
				if self.block_list[i].type == Block.LIVE:
					# 确定方向
					direction_able = [] # 可能的方向，不包括边界与死
					m_i = int(i / World.width)
					m_j = int(i) % World.width
					for j in range(4):
						t_i, t_j = World.to_direction(m_i, m_j, j)
						if t_i < 0 or t_i > World.height - 1 or t_j < 0 or t_j > World.width - 1:
							continue
						# if self.block_list[t_i * World.width + t_j].type == Block.DEAD:
						# 	continue
						# 0：左，1：上，2：右，3：下 
						# 读取相邻边
						side_self = []
						side_other = []
						#  0,  1,  2,  3
						#  4,  5,  6,  7
						#  8,  9, 10, 11
						# 12, 13, 14, 15
						if j == 0: # 左边
							for k in range(Common.BLOCK_size):
								side_self.append(self.block_list[i].grid[k * Common.BLOCK_size][0])
								side_other.append(self.block_list[t_i * World.width + t_j].grid[k * Common.BLOCK_size + Common.BLOCK_size - 1][0])
						if j == 1: # 上边
							for k in range(Common.BLOCK_size):
								side_self.append(self.block_list[i].grid[k][0])
								side_other.append(self.block_list[t_i * World.width + t_j].grid[k + Common.BLOCK_size * (Common.BLOCK_size - 1)][0])
						if j == 2: # 右边
							for k in range(Common.BLOCK_size):
								side_self.append(self.block_list[i].grid[k * Common.BLOCK_size + Common.BLOCK_size - 1][0])
								side_other.append(self.block_list[t_i * World.width + t_j].grid[k * Common.BLOCK_size][0])
						if j == 3: # 下边
							for k in range(Common.BLOCK_size):
								side_self.append(self.block_list[i].grid[k + Common.BLOCK_size * (Common.BLOCK_size - 1)][0])
								side_other.append(self.block_list[t_i * World.width + t_j].grid[k][0])
						if self.block_list[t_i * World.width + t_j].type == Block.DEAD:
							# 如果符合一定的判定条件，生可以与死交换
							flag = 1
							for k in range(len(side_self)):
								if side_self[k] * side_other[k] < 0: # 当且仅当相邻每一格符号相同，允许交换
									flag = 0
									break
							if flag == 0:
								continue
						# # 使用单一息的值判定块移动方向
						# # 人为设定从(0, 0, 3, 0, ...)开始判定块移动方向
						# start_place = pow(self.block_list[i].size, 2) * 3
						# info = self.block_list[i].grid_io(self.block_list[i], start_place + j, 0, 0)
						# direction_able.append([t_i, t_j, info])

						# # 使用矩阵乘判定块移动方向
						# mid_dot = np.dot(side_self, side_other)
						# direction_able.append([t_i, t_j, abs(mid_dot)])

						# 使用相邻素的差别来判定块移动方向
						mid_diff = 0
						for k in range(len(side_self)):
							mid_diff += abs(side_self[k] - side_other[k])
						direction_able.append([t_i, t_j, mid_diff])

						# # 对照实验，完全随机走
						# direction_able.append([t_i, t_j, random.random()]) # 对照实验，完全随机走
						
						# 使用简单指令进行移动
						# place_t = j + 2 + 3 * self.block_list[i].size * self.block_list[i].size # 2  3  4  5, 高为3
						# direction_able.append([t_i, t_j, self.block_list[i].grid[place_t]][0]) # 简单指令进行移动
					if len(direction_able) == 0:
						continue
					direction_min = min(direction_able, key = lambda x: x[2])
					t_i = direction_min[0]
					t_j = direction_min[1]
					move.append([m_i, m_j, t_i, t_j])
			# 结算，结算要独立放在交换之前，避免两生互换时的先手优势
			for i in range(len(move)):
				m_i, m_j, t_i, t_j = move[i]
				# 计算得分
				if self.block_list[t_i * World.width + t_j].type == Common.BLOCK_GOLD:
					self.block_list[t_i * World.width + t_j].type = Common.BLOCK_NONE
					self.block_list[m_i * World.width + m_j].score += 1
					self.block_list[m_i * World.width + m_j].time -= World.move_span * 5 # 得分使块年轻
					if self.block_list[m_i * World.width + m_j].time < 0: # 不允许积攒超过life_span的寿命
						self.block_list[m_i * World.width + m_j].time = 0
				# 计算神赐之种
				if self.block_list[t_i * World.width + t_j].type == Common.BLOCK_SEED:
					self.block_list[t_i * World.width + t_j].type = Common.BLOCK_NONE
					self.block_list[m_i * World.width + m_j].seed_num += 1 # 生吃到神赐之种
					# 随机生成新神赐之种
					s_i = random.randint(0, World.height - 1)
					s_j = random.randint(0, World.width - 1)
					while self.block_list[s_i * World.width + s_j].type != Common.BLOCK_NONE and \
					      self.block_list[s_i * World.width + s_j].type != Common.BLOCK_GOLD:
						s_i = random.randint(0, World.height - 1)
						s_j = random.randint(0, World.width - 1)
					self.block_list[s_i * World.width + s_j].type = Common.BLOCK_SEED
					# 记录神赐之种坐标
					self.seed_i = i
					self.seed_j = j
				# 掠夺
				if self.block_list[t_i * World.width + t_j].type == Common.BLOCK_LIVE:
					# 统计掠夺次数
					self.attack_all += 1
					# 掠夺
					self.block_list[t_i * World.width + t_j].time += World.move_span * 20 # 被交换的被掠夺寿命
					self.block_list[m_i * World.width + m_j].time -= World.move_span * 20 # 交换的获得寿命
					if self.block_list[m_i * World.width + m_j].time < 0: # 不允许积攒超过life_span的寿命
						self.block_list[m_i * World.width + m_j].time = 0
			# 交换块
			# 注意：两块互换会导致，先手生走两步（两生各自的方向），后手生被换到先手生的位置
			for i in range(len(move)):
				m_i, m_j, t_i, t_j = move[i]
				# 统计死被移动的次数
				if self.block_list[t_i * World.width + t_j].type == Common.BLOCK_DEAD:
					self.dead_move += 1
				# 交换块
				t = self.block_list[m_i * World.width + m_j]
				self.block_list[m_i * World.width + m_j] = self.block_list[t_i * World.width + t_j]
				self.block_list[t_i * World.width + t_j] = t
				# 修正位置
				self.block_list[t_i * World.width + t_j].b_i = t_i
				self.block_list[t_i * World.width + t_j].b_j = t_j
				self.block_list[m_i * World.width + m_j].b_i = m_i
				self.block_list[m_i * World.width + m_j].b_j = m_j
		# 统计生的寿命与分数
		for i in range(len(self.block_list)):
			if self.block_list[i].type == Block.LIVE:
				# 寿命减少，寿命到了删除，加入魂
				self.block_list[i].time += 1
				# 在结算死亡前结算神赐之种
				if self.block_list[i].time > World.life_span and self.block_list[i].seed_num > 0:
					self.block_list[i].time = 0
					self.block_list[i].seed_num -= 1
				# 结算死亡
				if self.block_list[i].time > World.life_span:
					# 统计得分
					self.score_all += self.block_list[i].score
					self.score_num += 1
					# 如果该生占用了神赐之脑，释放神赐之脑
					if self.brain_user == self.block_list[i]: # 当前生使用神赐之脑
						# 清除虚空链接
						self.block_list[i].connect = []
						still_connect = []
						for j in range(len(self.brain_list[0].connect)): # 只清除与生的连接
							if self.brain_list[0].connect[j][1] != self.block_list[i]:
								still_connect.append(self.brain_list[0].connect[j])
						self.brain_list[0].connect = still_connect
						# 标志神赐之脑未被占用
						self.brain_user = 0
						# 考虑有别的块的核已在虚空之脑内（只要新增运行的核都被清空就没事）
					# 如果魂满了，并且新的分高，直接拷贝
					if len(self.soul_list) > World.soul_num:
						if self.block_list[i].score > self.soul_list[-1].score:
							Block.copy(self.block_list[i], self.soul_list[-1])
					# 如果魂没满，新增入魂
					else:
						block_ = Block(1.0, 0, 0, self.ether_io)
						Block.copy(self.block_list[i], block_)
						self.soul_list.append(block_)
					self.soul_list = sorted(self.soul_list, key = lambda x: x.score, reverse = True)
					# 标为无，视为死亡
					self.block_list[i].type = Block.NONE
					self.block_list[i].core_list = []
					self.block_list[i].score = 0
					self.block_list[i].time = 0
		# 为第一名绑定神赐之脑
		if self.brain_user == 0: # 当前一名神赐之脑拥有者死亡
			# 挑选出当前得分最高的生
			block_list_t = sorted(self.block_list, key = lambda x: x.score, reverse = True)
			block_t = 0
			for i in range(len(block_list_t)): # 本循环为避免把神赐之脑赋给非生
				if block_list_t[i].type == Block.LIVE:
					block_t = block_list_t[i] 
					break
			# 建立生到神赐之脑的虚空连接
			for i in range(len(self.connect_list)): # [[0: 起点块, 1: 终点块, 2: 起点位置, 3: 终点位置], ...] block_t指代生
				start_block = self.connect_list[i][0]
				if start_block == 'block_t':
					start_block = block_t
				end_block = self.connect_list[i][1]
				if end_block == 'block_t':
					end_block = block_t
				start_place = self.connect_list[i][2]
				end_place = self.connect_list[i][3]
				start_block.connect.append([start_place, end_block, end_place])
			# 标志神赐之脑已被占用
			self.brain_user = block_t
			# 清空标记回路信息
			self.path = {}
			self.cycle = {}
			self.path_num = {}
		# 每隔一段时间投放生
		if self.time % World.put_span == 0:
			i = random.randint(0, len(self.block_list) - 1) # 随机生成位置
			if (self.block_list[i].type == Block.NONE or self.block_list[i].type == Common.BLOCK_GOLD) and len(self.soul_list) > 0: # 有空位才占
				if self.time % (World.put_span * 2) == 0:
					# 投放现存最高分的复制
					block_list_t = sorted(self.block_list, key = lambda x: x.score, reverse = True)
					Block.copy(block_list_t[0], self.block_list[i])
				else:
					# 从魂中挑选并投放生
					pick = self.pick()
					Block.copy(self.soul_list[pick], self.block_list[i])
				# 刷新寿命、分数、位置
				self.block_list[i].time = 0
				self.block_list[i].score = 0
				self.block_list[i].b_i = int(i / World.width)
				self.block_list[i].b_j = int(i) % World.width
				# 每次投放魂中的生都刷新核
				# 1、清空核
				self.block_list[i].core_list = []
				# 2、新增核
				# 新增核数量为格数量的十分之一
				new_core_num = int(0.1 * pow(self.block_list[i].size, self.block_list[i].dimension))
				for i_t in range(new_core_num): # 新增核数量
					core = Core(self.block_list[i])
		# 已有统计信息衰减（以显示较新数据）
		if self.time % World.statistic_span == 0:
			self.scar_active *= 0.9 # 刻印调用数量衰减
			self.tool_cycle_all *= 0.9 # 傀儡回路激活总数
			self.tool_cycle_num *= 0.9 # 傀儡回路回答正确次数
		# 每隔一段时间投放分数
		if self.time % int(World.move_span * 0.1) == 0: # 1
			i = random.randint(0, len(self.block_list) - 1) # 随机生成位置
			if self.block_list[i].type == Common.BLOCK_NONE:
				self.block_list[i].type = Common.BLOCK_GOLD
		# # 每隔一段时间刷新魂中的分数，避免没有生能超过最高分
		# if self.time % int(World.move_span * 10) == 0: # 100
		# 	# for i in range(1, len(self.soul_list)):
		# 	for i in range(len(self.soul_list)):
		# 		self.soul_list[i].score -= 1
		# 极慢随机更改刻印
		max_num = np.max(self.scar_active)
		for i in range(100): # 随机抽100个刻印的格做更改
			x = random.randint(1, len(self.scar) - 1) # 第一排长度为0的不管
			y = random.randint(0, len(self.scar[x]) - 1)
			z = random.randint(0, len(self.scar) - 1)
			if z > len(self.scar[x][y]) - 1: # 统一概率
				continue
			speed = 0.01 * (1 - self.scar_active[x][y] / max_num) # 更改速率 0.001
			# speed = 0
			if i % 2 == 0:
				self.scar[x][y][z] += speed
			else:
				self.scar[x][y][z] -= speed
			# 限制取值范围
			if self.scar[x][y][z] > 1.0:
				self.scar[x][y][z] = 1.0
			if self.scar[x][y][z] < -1.0:
				self.scar[x][y][z] = -1.0

	# io_type: 0: 读取，1: 写入，2: 判断出界
	def base_ether_io(self, block, place, move, io_type, data):
		# 1 找到place所在维度
		t_place = place
		t_move = move
		while abs(t_move) >= block.size:
			t_place = int(t_place / block.size)
			t_move = int(t_move / block.size)
		t_place = int(t_place) % block.size
		# 2 判断place加上move是否出界
		if t_place + t_move >= 0 and t_place + t_move <= block.size - 1:
			# 2.1 如果没有出界直接读取值并返回
			if io_type == 0:
				return block.grid[place + move][0]
			if io_type == 1:
				block.grid[place + move][0] = data
				return 1.0
			if io_type == 2:
				return 1
		else:
			if io_type == 2: # 返回已出界
				return 0
			if io_type == 1: # 不可以出界写
				return 0
			if io_type == 0: # 不可以出界读
				return 0.0

	# io_type: 0: 读取，1: 写入，2: 判断出界
	def motor_ether_io(self, block, place, move, io_type, data):
		move_duration = 0.01 # 每次生驱动电机持续时间 0.02
		back_duration = 10.0 # 校正回头持续时间
		max_range = 20.0 # 最大单向运动时间
		com_0 = 'COM8' # 串口
		com_1 = 'COM9' # 串口
		# 1 找到place所在维度
		t_place = place
		t_move = move
		while abs(t_move) >= block.size:
			t_place = int(t_place / block.size)
			t_move = int(t_move / block.size)
		t_place = int(t_place) % block.size
		# 2 判断place加上move是否出界
		if t_place + t_move >= 0 and t_place + t_move <= block.size - 1:
			# 2.1 如果没有出界直接读取值并返回
			if io_type == 0:
				return block.grid[place + move][0]
			if io_type == 1:
				# 控制电机
				if place + move == 42 and data > 0:
					thread = threading.Thread(target = self.set_motor, args=(com_0, move_duration, 1.0))
					thread.start()
				if place + move == 21 and data > 0:
					thread = threading.Thread(target = self.set_motor, args=(com_1, move_duration, -1.0))
					thread.start()  # 启动线程
				# # 校正电机位置
				# if abs(self.motor_place) > max_range:
				# 	if self.motor_place > 0:
				# 		thread = threading.Thread(target = self.set_motor, args=(com_1, back_duration, -1.0))
				# 		thread.start()  # 启动线程
				# 	else:
				# 		thread = threading.Thread(target = self.set_motor, args=(com_0, back_duration, 1.0))
				# 		thread.start()
				# 正常写入
				block.grid[place + move][0] = data
				return 1.0
			if io_type == 2:
				return 1
		else:
			if io_type == 2: # 返回已出界
				return 0
			if io_type == 1: # 不可以出界写
				return 0
			if io_type == 0: # 不可以出界读
				return 0.0

	# io_type: 0: 读取，1: 写入，2: 判断出界
	def camera_ether_io(self, block, place, move, io_type, data):
		# 1 找到place所在维度
		t_place = place
		t_move = move
		while abs(t_move) >= block.size:
			t_place = int(t_place / block.size)
			t_move = int(t_move / block.size)
		t_place = int(t_place) % block.size
		# 2 判断place加上move是否出界
		if t_place + t_move >= 0 and t_place + t_move <= block.size - 1:
			# 2.1 如果没有出界直接读取值并返回
			if io_type == 0:
				# 读取图像
				if place + move < block.size * block.size:
					i = int((place + move) / block.size)
					j = int(place + move) % block.size
					return self.img_use[i][j] / 255.0
				# 正常读取
				return block.grid[place + move][0]
			if io_type == 1:
				block.grid[place + move][0] = data
				return 1.0
			if io_type == 2:
				return 1
		else:
			if io_type == 2: # 返回已出界
				return 0
			if io_type == 1: # 不可以出界写
				return 0
			if io_type == 0: # 不可以出界读
				return 0.0

	# 包含对周围块类型读取
	# io_type: 0: 读取，1: 写入，2: 判断出界
	def round_ether_io(self, block, place, move, io_type, data):
		# 1 找到place所在维度
		t_place = place
		t_move = move
		while abs(t_move) >= block.size:
			t_place = int(t_place / block.size)
			t_move = int(t_move / block.size)
		t_place = int(t_place) % block.size
		# 2 判断place加上move是否出界
		if t_place + t_move >= 0 and t_place + t_move <= block.size - 1:
			# 2.1 如果没有出界直接读取值并返回
			if io_type == 0:
				return block.grid[place + move][0]
			if io_type == 1:
				block.grid[place + move][0] = data
				return 1.0
			if io_type == 2:
				return 1
		else:
			if io_type == 2: # 返回已出界
				return 0
			if io_type == 1: # 不可以出界写
				return 0
			# 2.2 如果出界则判断是否在接触面出界
			if move == -1 * pow(block.size, 2) and place < pow(block.size, 2): # 在前二维向下出界
				# 寻找到获得神赐之脑的生
				block_live = block.connect[0][2].connect[-1][2] # 先到中继，再到生
				# 确定要读取的位置
				b_i = block_live.b_i
				b_j = block_live.b_j
				place_i = int(place / block.size) # 0 1 2 3 (4) 5 6 7 8
				place_j = int(place) % block.size
				mid = int((block.size - 1) / 2)
				t_i = place_i - mid + b_i
				t_j = place_j - mid + b_j
				if t_i >= 0 and t_i < World.height and t_j >= 0 and t_j < World.width: # 在界内返回相应类型
					return float((self.block_list[t_i * World.width + t_j].type + 1.0) / 4.0)
				else: # 出界则返回0
					return 0.0
			# 2.2.3 如果不是在接触面出界则返回0.0
			return 0.0

	# 包含边界处理的读取/写入
	# io_type: 0: 读取，1: 写入，2: 判断出界
	def ether_io(self, block, place, move, io_type, data):
		b_i = block.b_i
		b_j = block.b_j
		# 1 找到place所在维度
		t_place = place
		t_move = move
		while abs(t_move) >= Common.BLOCK_size:
			t_place = int(t_place / Common.BLOCK_size)
			t_move = int(t_move / Common.BLOCK_size)
		t_place = int(t_place) % Common.BLOCK_size
		# 2 判断place加上move是否出界
		if t_place + t_move >= 0 and t_place + t_move <= Common.BLOCK_size - 1:
			# 2.1 如果没有出界直接读取值并返回
			if io_type == 0:
				# 人为设定的感官
				#  0  1  2  3  4  5  6  7
				#  8  9 10 11 12 13 14 15
				# 16 17 18 19 20 21 22 23
				# 24 25 26 27 28 29 30 31
				# 32 33 34 35 36 37 38 39
				# 40 41 42 43 44 45 46 47
				# 48 49 50 51 52 53 54 55
				# 56 57 58 59 60 61 62 63
				height = 2
				height_place = height * Common.BLOCK_size * Common.BLOCK_size
				if place + move == 42 + height_place: # 返回年龄
					# 统计探查年龄次数
					self.detect_age_all += 1
					# 返回年龄
					half =  float(World.life_span) / 2
					t = float(self.block_list[b_i * World.width + b_j].time - half) / half
					return t
				if place + move == 18 + height_place: # 返回横坐标
					# 统计横坐标探测次数
					self.detect_j_all += 1
					# 返回横坐标
					half =  float(World.width) / 2
					t = float(b_j - half) / half
					return t
				if place + move == 45 + height_place: # 返回纵坐标
					# 统计纵坐标探测次数
					self.detect_i_all += 1
					# 返回纵坐标
					half =  float(World.height) / 2
					t = float(b_i - half) / half
					return t
				if place + move == 21 + height_place: # 无意义点
					# 统计随机点探测次数
					self.detect_none_all += 1
				return self.block_list[b_i * World.width + b_j].grid[place + move][0]
			if io_type == 1:
				self.block_list[b_i * World.width + b_j].grid[place + move][0] = data
				return 1.0
			if io_type == 2:
				return 1
		else:
			if io_type == 2:
				return 0
			# 2.2 如果出界则判断是否在接触面出界
			if abs(move) < pow(Common.BLOCK_size, 2) and place < pow(Common.BLOCK_size, 2): # 在前二维移动
				# 2.2.1 如果在接触面出界则返回相邻块的接触面值
				if move == -1 * Common.BLOCK_size: # 向上出界
					if b_i == 0:
						return 0.0
					else:
						if io_type == 0:
							return self.block_list[(b_i - 1) * World.width + b_j].grid[place + pow(Common.BLOCK_size, 2) - Common.BLOCK_size][0]  # 画个x*x的格子对出来的
						if io_type == 1:
							self.block_list[(b_i - 1) * World.width + b_j].grid[place + pow(Common.BLOCK_size, 2) - Common.BLOCK_size][0] = data
							return 1.0
				if move == Common.BLOCK_size: # 向下出界
					if b_i == World.height - 1:
						return 0.0
					else:
						if io_type == 0:
							return self.block_list[(b_i + 1) * World.width + b_j].grid[place - pow(Common.BLOCK_size, 2) + Common.BLOCK_size][0]
						if io_type == 1:
							self.block_list[(b_i + 1) * World.width + b_j].grid[place - pow(Common.BLOCK_size, 2) + Common.BLOCK_size][0] = data
							return 1.0
				if move == -1: # 向左出界
					if b_j == 0:
						return 0.0
					else:
						if io_type == 0:
							return self.block_list[b_i * World.width + b_j - 1].grid[place + Common.BLOCK_size - 1][0]
						if io_type == 1:
							self.block_list[b_i * World.width + b_j - 1].grid[place + Common.BLOCK_size - 1][0] = data
							return 1.0
				if move == 1: # 向右出界
					if b_j == World.width - 1:
						return 0.0
					else:
						if io_type == 0:
							return self.block_list[b_i * World.width + b_j + 1].grid[place - Common.BLOCK_size + 1][0]
						if io_type == 1:
							self.block_list[b_i * World.width + b_j + 1].grid[place - Common.BLOCK_size + 1][0] = data
							return 1.0
			# # 2.2.2 人为设定的感官
			# if move == -1 * pow(Common.BLOCK_size, 2) and place < pow(Common.BLOCK_size, 2) and io_type == 0: # 在前二维沿第三维出界，且是读取
			# 	#  0  1  2  3  4  5  6  7
			# 	#  8  9 10 11 12 13 14 15
			# 	# 16 17 18 19 20 21 22 23
			# 	# 24 25 26 27 28 29 30 31
			# 	# 32 33 34 35 36 37 38 39
			# 	# 40 41 42 43 44 45 46 47
			# 	# 48 49 50 51 52 53 54 55
			# 	# 56 57 58 59 60 61 62 63
			# 	if place == 42: # 返回年龄
			# 		# 统计探查年龄次数
			# 		self.detect_age_all += 1
			# 		# 返回年龄
			# 		half =  float(World.life_span) / 2
			# 		t = float(self.block_list[b_i * World.width + b_j].time - half) / half
			# 		return t
			# 	if place == 18: # 返回横坐标
			# 		# 统计横坐标探测次数
			# 		self.detect_j_all += 1
			# 		# 返回横坐标
			# 		half =  float(World.width) / 2
			# 		t = float(b_j - half) / half
			# 		return t
			# 	if place == 45: # 返回纵坐标
			# 		# 统计纵坐标探测次数
			# 		self.detect_i_all += 1
			# 		# 返回纵坐标
			# 		half =  float(World.height) / 2
			# 		t = float(b_i - half) / half
			# 		return t
			# 	if place == 21: # 无意义点
			# 		# 统计随机点探测次数
			# 		self.detect_none_all += 1
			# 2.2.3 如果不是在接触面出界则返回0.0
			return 0.0

	# 判定是否通过虚空连接
	# 虚空连接: [[0: 起点位置, 1: 目标块, 2: 终点位置], ...]
	def grid_io_connect(self, block, place, io_type, data):
		connect = block.connect
		for i in range(len(connect)):
			if connect[i][0] == place: # 符合虚空连接
				# 虚空连接不得嵌套，避免死循环
				aim_block = connect[i][1] # 目标块
				aim_place = connect[i][2] # 目标坐标
				if io_type == 0: # 读取息
					return aim_block.grid[aim_place][0]
				if io_type == 1: # 写入息
					aim_block.grid[aim_place][0] = data
					return
				if io_type == 2: # 读取素
					return aim_block.grid[aim_place][1]
				if io_type == 3: # 写入素
					aim_block.grid[aim_place][1] = data
					return
		return 42

	# 通的实现
	# io_type: 0: 读取息，1: 写入息，2: 读取素，3: 写入素
	def basic_grid_io(self, block, place, io_type, data):
		# 先判定虚空连接
		result = self.grid_io_connect(block, place, io_type, data)
		if result != 42: # 已通过虚空连接
			return result
		# 统计信息
		if block == self.brain_list[1] and place < pow(block.size, 2) and io_type == 0:
			self.none_brain_num += 1
		# 输入输出
		if io_type == 0: # 读取息
			return block.grid[place][0]
		if io_type == 1: # 写入息
			block.grid[place][0] = data
			return
		if io_type == 2: # 读取素
			return block.grid[place][1]
		if io_type == 3: # 写入素
			block.grid[place][1] = data
			return

	# 通的实现
	# io_type: 0: 读取息，1: 写入息，2: 读取素，3: 写入素
	def info_grid_io(self, block, place, io_type, data):
		# 先判定虚空连接
		result = self.grid_io_connect(block, place, io_type, data)
		if result != 42: # 已通过虚空连接
			return result
		# 对于信息的探测
		info_num = 6
		if place < pow(block.size, 2) and io_type == 0:
			if place % info_num == 0: # 返回年龄
				# 返回年龄
				half = float(World.life_span) / 2
				t = float(self.brain_user.time - half) / half
				return t
			if place % info_num == 1: # 返回横坐标
				# 返回横坐标
				half = float(World.width) / 2
				t = float(self.brain_user.b_j - half) / half
				return t
			if place % info_num == 2: # 返回纵坐标
				# 返回纵坐标
				half = float(World.height) / 2
				t = float(self.brain_user.b_i - half) / half
				return t
			if place % info_num == 3: # 返回神赐之种横坐标
				# 返回横坐标
				half = float(World.width) / 2
				t = float(self.seed_j - half) / half
				return t
			if place % info_num == 4: # 返回神赐之种纵坐标
				# 返回纵坐标
				half = float(World.height) / 2
				t = float(self.seed_i - half) / half
				return t
			if place % info_num == 5: # 返回拥有神赐之种数量
				half = 5.0 / 2
				t = float(self.brain_user.seed_num - half) / half
				return t
		# 输入输出
		if io_type == 0: # 读取息
			return block.grid[place][0]
		if io_type == 1: # 写入息
			block.grid[place][0] = data
			return
		if io_type == 2: # 读取素
			return block.grid[place][1]
		if io_type == 3: # 写入素
			block.grid[place][1] = data
			return

	# 通的实现
	# io_type: 0: 读取息，1: 写入息，2: 读取素，3: 写入素
	def operator_grid_io(self, block, place, io_type, data):
		# 先判定虚空连接
		result = self.grid_io_connect(block, place, io_type, data)
		if result != 42: # 已通过虚空连接
			return result
		# 各运算符的实现
		if place < 42 and io_type == 0:
			if place == 2: # +
				return block.grid[place - 2][0] + block.grid[place - 1][0]
			if place == 5: # -
				return block.grid[place - 2][0] - block.grid[place - 1][0]
			if place == 8: # *
				return block.grid[place - 2][0] * block.grid[place - 1][0]
			if place == 11: # /
				if block.grid[place - 1][0] != 0:
					return block.grid[place - 2][0] / block.grid[place - 1][0]
				else:
					return 0.0
			# if place == 14: # ^
			# 	return pow(abs(block.grid[place - 2][0]), block.grid[place - 1][0])
			if place == 16: # !
				if block.grid[place - 1][0] < 0:
					return 0.5
				else:
					return -0.5
			if place == 19: # *-1.0
				return block.grid[place - 1][0] * -1.0
			if place == 21: # ||
				if block.grid[place - 2][0] > 0 or block.grid[place - 1][0] > 0:
					return 0.5
				else:
					return -0.5
			if place == 24: # &&
				if block.grid[place - 2][0] > 0 and block.grid[place - 1][0] > 0:
					return 0.5
				else:
					return -0.5
			if place == 27: # >
				if block.grid[place - 2][0] > block.grid[place - 1][0] > 0:
					return 0.5
				else:
					return -0.5
			if place == 30: # <
				if block.grid[place - 2][0] < block.grid[place - 1][0] > 0:
					return 0.5
				else:
					return -0.5
			if place == 33: # ==
				if block.grid[place - 2][0] == block.grid[place - 1][0] > 0:
					return 0.5
				else:
					return -0.5
			if place == 36: # max
				if block.grid[place - 2][0] > block.grid[place - 1][0] > 0:
					return block.grid[place - 2][0]
				else:
					return block.grid[place - 1][0]
			if place == 39: # min
				if block.grid[place - 2][0] < block.grid[place - 1][0] > 0:
					return block.grid[place - 2][0]
				else:
					return block.grid[place - 1][0]
			if place == 41: # abs
				return abs(block.grid[place - 1][0])
		# 输入输出
		if io_type == 0: # 读取息
			return block.grid[place][0]
		if io_type == 1: # 写入息
			block.grid[place][0] = data
			return
		if io_type == 2: # 读取素
			return block.grid[place][1]
		if io_type == 3: # 写入素
			block.grid[place][1] = data
			return

	# 通的实现
	# io_type: 0: 读取息，1: 写入息，2: 读取素，3: 写入素
	def round_grid_io(self, block, place, io_type, data):
		# 先判定虚空连接
		result = self.grid_io_connect(block, place, io_type, data)
		if result != 42: # 已通过虚空连接
			return result
		# 未通过虚空连接
		aim_block = block # 目标块
		aim_place = place # 目标坐标
		# 对于周围环境的探测
		if place < pow(block.size, 2) and io_type == 0:
			self.round_brain_num += 1
			# 寻找到获得神赐之脑的生
			block_live = self.brain_user
			# 确定要读取的位置
			b_i = block_live.b_i
			b_j = block_live.b_j
			place_i = int(place / block.size) # 0 1 2 3 (4) 5 6 7
			place_j = int(place) % block.size
			mid = int(block.size / 2)
			t_i = place_i - mid + b_i
			t_j = place_j - mid + b_j
			if t_i >= 0 and t_i < World.height and t_j >= 0 and t_j < World.width: # 在界内返回相应类型
				return float((self.block_list[t_i * World.width + t_j].type) / 2.0 - 1.0 )
			else: # 出界则返回0
				return 0.0
		# 输入输出
		if io_type == 0: # 读取息
			return aim_block.grid[aim_place][0]
		if io_type == 1: # 写入息
			aim_block.grid[aim_place][0] = data
			return
		if io_type == 2: # 读取素
			return aim_block.grid[aim_place][1]
		if io_type == 3: # 写入素
			aim_block.grid[aim_place][1] = data
			return

	# 通的实现
	# {通}是块感知、影响环境的手段。实现方式为：当块内指定坐标【息】、【素】被读取或写入，改为读取或写入块外指定坐标【息】、【素】。
	# io_type: 0: 读取息，1: 写入息，2: 读取素，3: 写入素
	def world_grid_io(self, block, place, io_type, data):
		# 先判定虚空连接
		result = self.grid_io_connect(block, place, io_type, data)
		if result != 42: # 已通过虚空连接
			return result
		# 未通过虚空连接
		aim_block = block # 目标块
		aim_place = place # 目标坐标
		# 人为设定从(0, 0, 1, 0, ...)开始建立通，(0, 0, 0)到(0, 0, 1)涉及块的交换判定，暂不使用
		start_place = pow(block.size, 2) 
		# 对于块上下左右四条邻边的读写
		if place >= start_place and place < start_place + 4 * block.size:
			# 占用4条长度为块尺寸的格，分别实现上下左右四边的通：
			# 0 、上边，1 、下边，2 、左边，3 ，右边
			abs_place = place - start_place # 坐标相对通起点的偏移
			# 上边
			if abs_place >= 0 and abs_place < block.size:
				if block.b_i == 0: # 块已经位于最上边
					return 0.0
				aim_block = self.block_list[(block.b_i - 1) * World.width + block.b_j]
				aim_place = abs_place + pow(block.size, 2) - block.size
			# 下边
			if abs_place >= block.size and abs_place < block.size * 2:
				if block.b_i == World.height - 1: # 块已经位于最下边
					return 0.0
				aim_block = self.block_list[(block.b_i + 1) * World.width + block.b_j]
				the_palce = abs_place - block.size # 坐标相对边起点的偏移
				aim_place = the_palce
			# 左边
			if abs_place >= block.size * 2 and abs_place < block.size * 3:
				if block.b_j == 0: # 块已经位于最左边
					return 0.0
				aim_block = self.block_list[block.b_i * World.width + block.b_j - 1]
				the_palce = abs_place - block.size * 2 # 坐标相对边起点的偏移
				aim_place = the_palce * block.size
			# 右边
			if abs_place >= block.size * 3 and abs_place < block.size * 4:
				if block.b_j == World.width - 1: # 块已经位于最右边
					return 0.0
				aim_block = self.block_list[block.b_i * World.width + block.b_j + 1]
				the_palce = abs_place - block.size * 3 # 坐标相对边起点的偏移
				aim_place = the_palce * block.size + (block.size - 1)
		# 对于块年龄、位置的探测
		if place >= start_place + 4 * block.size and place < start_place + 4 * block.size + 4:
			abs_place = place - (start_place + 4 * block.size)
			if abs_place == 0 and io_type == 0: # 返回年龄
				# 统计探查年龄次数
				self.detect_age_all += 1
				# 返回年龄
				half = float(World.life_span) / 2
				t = float(block.time - half) / half
				return t
			if abs_place == 1 and io_type == 0: # 返回横坐标
				# 统计横坐标探测次数
				self.detect_j_all += 1
				# 返回横坐标
				half = float(World.width) / 2
				t = float(block.b_j - half) / half
				return t
			if abs_place == 2 and io_type == 0: # 返回纵坐标
				# 统计纵坐标探测次数
				self.detect_i_all += 1
				# 返回纵坐标
				half = float(World.height) / 2
				t = float(block.b_i - half) / half
				return t
			if abs_place == 3 and io_type == 0: # 无意义点
				# 统计随机点探测次数
				self.detect_none_all += 1
		# 各运算符的实现
		if place >= start_place + 4 * block.size + 4 and \
		   place < start_place + 4 * block.size + 4 + 42 and \
		   (io_type == 0 or io_type == 2):
			abs_place = place - (start_place + 4 * block.size + 4)
			if io_type == 0:
				grid_type = 0
			else:
				grid_type = 1
			if abs_place == 2: # +
				return block.grid[place - 2][grid_type] + block.grid[place - 1][grid_type]
			if abs_place == 5: # -
				return block.grid[place - 2][grid_type] - block.grid[place - 1][grid_type]
			if abs_place == 8: # *
				return block.grid[place - 2][grid_type] * block.grid[place - 1][grid_type]
			if abs_place == 11: # /
				if block.grid[place - 1][grid_type] != 0:
					return block.grid[place - 2][grid_type] / block.grid[place - 1][grid_type]
				else:
					return 0.0
			# if abs_place == 14: # ^
			# 	return pow(abs(block.grid[place - 2][0]), block.grid[place - 1][0])
			if abs_place == 16: # !
				if block.grid[place - 1][grid_type] < 0:
					return 0.5
				else:
					return -0.5
			if abs_place == 19: # *-1.0
				return block.grid[place - 1][grid_type] * -1.0
			if abs_place == 21: # ||
				if block.grid[place - 2][grid_type] > 0 or block.grid[place - 1][grid_type] > 0:
					return 0.5
				else:
					return -0.5
			if abs_place == 24: # &&
				if block.grid[place - 2][grid_type] > 0 and block.grid[place - 1][grid_type] > 0:
					return 0.5
				else:
					return -0.5
			if abs_place == 27: # >
				if block.grid[place - 2][grid_type] > block.grid[place - 1][grid_type] > 0:
					return 0.5
				else:
					return -0.5
			if abs_place == 30: # <
				if block.grid[place - 2][grid_type] < block.grid[place - 1][grid_type] > 0:
					return 0.5
				else:
					return -0.5
			if abs_place == 33: # ==
				if block.grid[place - 2][grid_type] == block.grid[place - 1][grid_type] > 0:
					return 0.5
				else:
					return -0.5
			if abs_place == 36: # max
				if block.grid[place - 2][grid_type] > block.grid[place - 1][grid_type] > 0:
					return block.grid[place - 2][grid_type]
				else:
					return block.grid[place - 1][grid_type]
			if abs_place == 39: # min
				if block.grid[place - 2][grid_type] < block.grid[place - 1][grid_type] > 0:
					return block.grid[place - 2][grid_type]
				else:
					return block.grid[place - 1][grid_type]
			if abs_place == 41: # abs
				return abs(block.grid[place - 1][grid_type])
		# 输入输出
		if io_type == 0: # 读取息
			return aim_block.grid[aim_place][0]
		if io_type == 1: # 写入息
			aim_block.grid[aim_place][0] = data
			return
		if io_type == 2: # 读取素
			return aim_block.grid[aim_place][1]
		if io_type == 3: # 写入素
			aim_block.grid[aim_place][1] = data
			return

	# 绘制世界
	def draw_world(self, name):
		fig_size = 8.0 # 10.0
		fig = plt.figure(figsize = (fig_size, fig_size * 2.3)) # 调整大小
		# 绘制世界热力图
		# https://matplotlib.org/stable/gallery/color/colormap_reference.html      Colormap参考
		ax = plt.subplot2grid((2, 1), (0, 0))
		data = []
		for i in range(World.height):
			one_data = []
			for j in range(World.width):
				type_t = self.block_list[i * World.width + j].type
				# 得分点单独画
				if type_t == Common.BLOCK_GOLD or type_t == Common.BLOCK_SEED:
					type_t = Common.BLOCK_NONE
				one_data.append(type_t)
			data.append(one_data)
		im = ax.imshow(data, cmap = plt.cm.PiYG) 
		ax.yaxis.set_major_locator(plt.NullLocator()) # 同时隐藏刻度和坐标轴标签
		ax.xaxis.set_major_locator(plt.NullLocator())
		ax.spines['top'].set_color('none') # 去除边框
		ax.spines['bottom'].set_color('none')
		ax.spines['left'].set_color('none')
		ax.spines['right'].set_color('none')
		# 绘制得分点
		for i in range(World.height):
			for j in range(World.width):
				if self.block_list[i * World.width + j].type == Common.BLOCK_GOLD:
						plt.scatter(j, i, s = fig_size * 10.0 , facecolors = 'y')
				if self.block_list[i * World.width + j].type == Common.BLOCK_SEED:
						plt.scatter(j, i, s = fig_size * 10.0 , facecolors = 'c')
		# 标记分数最高的生
		block_list_t = sorted(self.block_list, key = lambda x: x.score, reverse = True)
		block_list_sorted = []
		# 只用生填充
		for i in range(len(block_list_t)):
			if block_list_t[i].type == Block.LIVE:
				block_list_sorted.append(block_list_t[i])
			if len(block_list_sorted) > 3:
				break
		for i in range(len(block_list_sorted)):
			plt.text(block_list_sorted[i].b_j, block_list_sorted[i].b_i, str(i), color = 'w', va = 'center', ha = 'center', size = fig_size * 2)
		# 绘制标题
		plt.title('Version: ' + name + '\nTime: ' + str(self.time), size = fig_size * 2.0, loc = 'left') # 标题
		# 绘制数据
		place_0 = 0
		place_1 = int(World.width / 3)
		place_2 = int(World.width / 3 * 2)
		info_size = fig_size * 1.8
		# 当前生、金数量
		live_num = 0
		gold_num = 0
		for i in range(len(self.block_list)):
			if self.block_list[i].type == Common.BLOCK_LIVE:
				live_num += 1
			if self.block_list[i].type == Common.BLOCK_GOLD:
				gold_num += 1
		plt.text(place_1, -11.5, 'Gold Num: ' + str(gold_num), color = 'k', va = 'center', ha = 'left', size = info_size)
		plt.text(place_1, -9.5, 'Live Num: ' + str(live_num), color = 'k', va = 'center', ha = 'left', size = info_size)
		# 最高分
		max_score = 0
		if len(self.soul_list) > 0:
			max_score = self.soul_list[0].score
		plt.text(place_1, -5.5, 'Max Score: ' + str(max_score), color = 'k', va = 'center', ha = 'left', size = info_size)
		# 平均分
		avg_score = 0.0
		if self.score_num != 0:
			avg_score = float(self.score_all) / self.score_num
		avg_score = round(avg_score, 2)
		plt.text(place_1, -3.5, 'Avg Score: ' + str(avg_score), color = 'k', va = 'center', ha = 'left', size = info_size)
		# 死被移动的次数
		avg_ = 0.0
		if self.score_num != 0:
			avg_ = float(self.dead_move) / self.score_num
		avg_ = round(avg_, 2)
		plt.text(place_1, -1.5, 'Dead Move: ' + str(avg_), color = 'k', va = 'center', ha = 'left', size = info_size)
		# 平均无意义探测次数
		avg_ = 0.0
		if self.score_num != 0:
			avg_ = float(self.detect_none_all) / self.score_num
		avg_ = round(avg_, 2)
		plt.text(place_2, -9.5, 'None Detect: ' + str(avg_), color = 'k', va = 'center', ha = 'left', size = info_size)
		# 平均横坐标探测次数
		avg_ = 0.0
		if self.score_num != 0:
			avg_ = float(self.detect_i_all) / self.score_num
		avg_ = round(avg_, 2)
		plt.text(place_2, -7.5, 'Vertical Detect: ' + str(avg_), color = 'k', va = 'center', ha = 'left', size = info_size)
		# 平均横坐标探测次数
		avg_ = 0.0
		if self.score_num != 0:
			avg_ = float(self.detect_j_all) / self.score_num
		avg_ = round(avg_, 2)
		plt.text(place_2, -5.5, 'Horizon Detect: ' + str(avg_), color = 'k', va = 'center', ha = 'left', size = info_size)
		# 平均寿命探测次数
		avg_detect_age = 0.0
		if self.score_num != 0:
			avg_detect_age = float(self.detect_age_all) / self.score_num
		avg_detect_age = round(avg_detect_age, 2)
		plt.text(place_2, -3.5, 'Age Detect: ' + str(avg_detect_age), color = 'k', va = 'center', ha = 'left', size = info_size)
		# 平均掠夺次数
		avg_attack = 0.0
		if self.score_num != 0:
			avg_attack = float(self.attack_all) / self.score_num
		avg_attack = round(avg_attack, 2)
		plt.text(place_2, -1.5, 'Attack: ' + str(avg_attack), color = 'k', va = 'center', ha = 'left', size = info_size)
		# # 空白运算读取次数
		# avg_ = 0.0
		# if self.score_num != 0:
		# 	avg_ = float(self.none_brain_num) / self.score_num
		# avg_ = round(avg_, 2)
		# plt.text(place_0, -15.5, 'None: ' + str(avg_), color = 'k', va = 'center', ha = 'left', size = info_size)
		# # 周围环境读取次数
		# avg_ = 0.0
		# if self.score_num != 0:
		# 	avg_ = float(self.round_brain_num) / self.score_num
		# avg_ = round(avg_, 2)
		# plt.text(place_0, -13.5, 'Round: ' + str(avg_), color = 'k', va = 'center', ha = 'left', size = info_size)
		# # 与运算读取次数
		# avg_ = 0.0
		# if self.score_num != 0:
		# 	avg_ = float(self.and_brain_num) * 3.0 / self.score_num
		# avg_ = round(avg_, 2)
		# plt.text(place_0, -11.5, 'And: ' + str(avg_), color = 'k', va = 'center', ha = 'left', size = info_size)
		# # 或运算读取次数
		# avg_ = 0.0
		# if self.score_num != 0:
		# 	avg_ = float(self.or_brain_num) * 3.0 / self.score_num
		# avg_ = round(avg_, 2)
		# plt.text(place_0, -9.5, 'Or: ' + str(avg_), color = 'k', va = 'center', ha = 'left', size = info_size)
		# # 非运算读取次数
		# avg_ = 0.0
		# if self.score_num != 0:
		# 	avg_ = float(self.not_brain_num) * 2.0 / self.score_num
		# avg_ = round(avg_, 2)
		# plt.text(place_0, -7.5, 'Not: ' + str(avg_), color = 'k', va = 'center', ha = 'left', size = info_size)
		# # 与运算返回正
		# avg_ = 0.0
		# if self.and_brain_num != 0:
		# 	avg_ = float(self.and_brain_yes_num) / self.and_brain_num
		# avg_ = round(avg_, 2)
		# plt.text(place_2, -15.5, 'And Yes: ' + str(avg_), color = 'k', va = 'center', ha = 'left', size = info_size)
		# # 或运算返回正
		# avg_ = 0.0
		# if self.or_brain_num != 0:	
		# 	avg_ = float(self.or_brain_yes_num) / self.or_brain_num
		# avg_ = round(avg_, 2)
		# plt.text(place_2, -13.5, 'Or Yes: ' + str(avg_), color = 'k', va = 'center', ha = 'left', size = info_size)
		# # 非运算返回正
		# avg_ = 0.0
		# if self.not_brain_num != 0:	
		# 	avg_ = float(self.not_brain_yes_num) / self.not_brain_num
		# avg_ = round(avg_, 2)
		# plt.text(place_2, -11.5, 'Not Yes: ' + str(avg_), color = 'k', va = 'center', ha = 'left', size = info_size)
		# 傀儡回路回答正确概率
		avg_ = 0.0
		if self.tool_cycle_all != 0:
			avg_ = float(self.tool_cycle_num) / self.tool_cycle_all
		avg_ = round(avg_, 2)
		plt.text(place_0, -7.5, 'Tool Yes: ' + str(avg_), color = 'k', va = 'center', ha = 'left', size = info_size)
		plt.text(place_0, -9.5, 'Tool All: ' + str(round(self.tool_cycle_all, 2)), color = 'k', va = 'center', ha = 'left', size = info_size)
		# 魂信息
		soul_str = 'Soul List: '
		for i in range(min(len(self.soul_list), 5)):
			soul_str += str(self.soul_list[i].score) + ', '
		soul_str = soul_str[:-2]
		plt.text(0, World.height + 0.5, soul_str, color = 'k', va = 'center', ha = 'left', size = info_size)

		# 绘制块热力图
		place = [(2, 0), (2, 1), (3, 0), (3, 1)]
		for i in range(len(block_list_sorted)):
			ax = plt.subplot2grid((4, 2), place[i])
			# 包含上下左右四个框的数据
			data = []
			# .1 上边
			one_data = []
			one_data.append(0.0)
			for j in range(Common.BLOCK_size):
				one_data.append(self.ether_io(block_list_sorted[i], j, -1 * Common.BLOCK_size, 0, 0))
			one_data.append(0.0)
			data.append(one_data)
			# .2 中段
			for j in range(Common.BLOCK_size):
				one_data = []
				one_data.append(self.ether_io(block_list_sorted[i], j * Common.BLOCK_size, -1, 0, 0))
				for k in range(Common.BLOCK_size):
					one_data.append(block_list_sorted[i].grid[j * Common.BLOCK_size + k][0])
				one_data.append(self.ether_io(block_list_sorted[i], j * Common.BLOCK_size + Common.BLOCK_size - 1, 1, 0, 0))
				data.append(one_data)
			# .1 下边
			one_data = []
			one_data.append(0.0)
			for j in range(Common.BLOCK_size):
				one_data.append(self.ether_io(block_list_sorted[i], j + Common.BLOCK_size * (Common.BLOCK_size - 1), Common.BLOCK_size, 0, 0))
			one_data.append(0.0)
			data.append(one_data)
			# 绘制热力图
			im = ax.imshow(data, cmap = plt.cm.RdYlGn) 
			plt.text(Common.BLOCK_size + 2, Common.BLOCK_size + 2, str(i), va = 'bottom', ha = 'right', size = fig_size * 4) #绘制块标记
			ax.yaxis.set_major_locator(plt.NullLocator()) # 同时隐藏刻度和坐标轴标签
			ax.xaxis.set_major_locator(plt.NullLocator())
			ax.spines['top'].set_color('none') # 去除边框
			ax.spines['bottom'].set_color('none')
			ax.spines['left'].set_color('none')
			ax.spines['right'].set_color('none')
			# 绘制块边界
			plt.plot([0.5, Common.BLOCK_size + 0.5], [0.5, 0.5], 'k', linewidth = fig_size / 4)
			plt.plot([0.5, Common.BLOCK_size + 0.5], [Common.BLOCK_size + 0.5, Common.BLOCK_size + 0.5], 'k', linewidth = fig_size / 4)
			plt.plot([0.5, 0.5], [Common.BLOCK_size + 0.5, 0.5], 'k', linewidth = fig_size / 4)
			plt.plot([Common.BLOCK_size + 0.5, Common.BLOCK_size + 0.5], [Common.BLOCK_size + 0.5, 0.5], 'k', linewidth = fig_size / 4)
			# 绘制核
			core_list = block_list_sorted[i].core_list
			for j in range(len(core_list)):
				if core_list[j].place_block != block_list_sorted[i]: # 只绘制本块的核
					continue
				t_place = core_list[j].place
				if t_place < Common.BLOCK_size * Common.BLOCK_size:
					# 绘制最底层，如果是二维则绘制数字
					t_i = int(t_place / Common.BLOCK_size)
					t_j = int(t_place) % Common.BLOCK_size
					plt.text(t_j + 1, t_i + 1, str(k), va = 'center', ha = 'center', size = fig_size * 2.0)
				if t_place >= Common.BLOCK_size * Common.BLOCK_size and t_place < Common.BLOCK_size * Common.BLOCK_size * Common.BLOCK_size:
					# 如果是3维的则绘制表示高度的圆圈
					t_m = t_place
					t_j = int(t_m) % Common.BLOCK_size
					t_m = int(t_place / Common.BLOCK_size)
					t_i = int(t_m) % Common.BLOCK_size
					t_k = int(t_m / Common.BLOCK_size) # t_k是第三维的高
					c_k = (t_k % 2) * 0.3 + t_k * 0.1
					plt.scatter(t_j + 1, t_i + 1, s = t_k * fig_size * 10.0 , facecolors = 'none', edgecolors = plt.cm.gist_yarg(c_k), linewidths = fig_size / 7.0)

			# 绘制标题
			plt.title('Score:' + str(block_list_sorted[i].score) + '\nAge: ' + str(block_list_sorted[i].time), size = fig_size * 2, loc = 'left') # 标题
			plt.text(float(Common.BLOCK_size) / 2.0 + 1.0, -0.8, 'Seed: ' + str(block_list_sorted[i].seed_num), \
			         color = 'k', va = 'center', ha = 'left', size = fig_size * 2)

		# plt.show()
		s = '%09d' % self.time
		file_name = './result-' + name + '/pic-1/' + s + '.png'
		plt.savefig(file_name)
		plt.close()

		# 绘制神赐之脑		
		round_brain = self.brain_list[2]
		fig = plt.figure(figsize = (fig_size * 0.55, fig_size * 0.55))
		ax = plt.axes(projection='3d')
		# 绘制底部环境信息
		block_live = self.brain_user # 寻找到获得神赐之脑的生
		b_i = block_live.b_i
		b_j = block_live.b_j
		mid = int(round_brain.size / 2) # 0 1 2 3 (4) 5 6 7
		c_data = 0
		for i in range(round_brain.size):
			for j in range(round_brain.size):
				type_t = 0
				t_i = i - mid + b_i
				t_j = j - mid + b_j
				if t_i >= 0 and t_i < World.height and t_j >= 0 and t_j < World.width: # 在界内返回相应类型
					type_t = self.block_list[t_i * World.width + t_j].type
				else: # 出界显示死
					type_t = Common.BLOCK_DEAD
				if type_t == Common.BLOCK_LIVE:
					c_data = 'r'
				if type_t == Common.BLOCK_DEAD:
					c_data = 'w'
				if type_t == Common.BLOCK_NONE:
					c_data = 'g'
				if type_t == Common.BLOCK_GOLD:
					c_data = 'y'
				ax.scatter3D(j + 0.5, i + 0.5, 0.5, c = c_data, s = fig_size * 20.0, alpha = 0.5)
		# 绘制核
		# 绘制核的圈
		x_data = []
		y_data = []
		z_data = []
		for i in range(len(block_live.core_list)):
			if block_live.core_list[i].place_block == round_brain:
				place = block_live.core_list[i].place
				z = int(place / (round_brain.size * round_brain.size))
				t = int(place) % (round_brain.size * round_brain.size)
				y = int(t / round_brain.size)
				x = int(t) % round_brain.size
				x_data.append(x + 0.5)
				y_data.append(y + 0.5)
				z_data.append(z + 0.5)
		ax.scatter3D(x_data, y_data, z_data, color = 'k', s = fig_size * 30.0, alpha = 0.5)
		# 绘制统计神赐之脑内的数据流向
		for i in range(len(self.grid_io_log)): # [[块, 类型, 起点坐标, 终点坐标], ...]
			if self.grid_io_log[i][0] != round_brain:
				continue
			x = [self.grid_io_log[i][2][0] + 0.5, self.grid_io_log[i][3][0] + 0.5]
			y = [self.grid_io_log[i][2][1] + 0.5, self.grid_io_log[i][3][1] + 0.5]
			z = [self.grid_io_log[i][2][2] + 0.5, self.grid_io_log[i][3][2] + 0.5]
			if self.grid_io_log[i][1] == 1: # 1、更改指定息
				ax.plot3D(x, y, z, color = 'c', linewidth = fig_size * 0.2) # m: 品红, c: 青
				ax.scatter3D(x[1], y[1], z[1], color = 'c', marker = 'h', s = fig_size * 30.0, alpha = 0.5)
			if self.grid_io_log[i][1] == 2: # 2、更改指定素
				ax.plot3D(x, y, z, color = 'm', linewidth = fig_size * 0.2)
				ax.scatter3D(x[1], y[1], z[1], color = 'm', marker = 'h', s = fig_size * 30.0, alpha = 0.5)
			if self.grid_io_log[i][1] == 5: # 5、随机化指定息
				ax.scatter3D(x[0], y[0], z[0], color = 'c', marker = 'x', s = fig_size * 30.0)
			if self.grid_io_log[i][1] == 6: # 6、随机化指定素
				ax.scatter3D(x[0], y[0], z[0], color = 'm', marker = 'x', s = fig_size * 30.0)
		# 绘制虚空连接点位
		x_data_in = []
		y_data_in = []
		z_data_in = []
		x_data_out = []
		y_data_out = []
		z_data_out = []
		for i in range(len(round_brain.connect)):
			t = round_brain.connect[i][0] # 出
			x = t % round_brain.size
			t = int(t / round_brain.size)
			y = t % round_brain.size
			z = int(t / round_brain.size)
			x_data_out.append(x + 0.5)
			y_data_out.append(y + 0.5)
			z_data_out.append(z + 0.5)
		front_brain = self.brain_list[0]
		for i in range(len(front_brain.connect)):
			if front_brain.connect[i][1] == round_brain:
				t = front_brain.connect[i][2] # 入
				x = t % round_brain.size
				t = int(t / round_brain.size)
				y = t % round_brain.size
				z = int(t / round_brain.size)
				x_data_in.append(x + 0.5)
				y_data_in.append(y + 0.5)
				z_data_in.append(z + 0.5)
		ax.scatter3D(x_data_in, y_data_in, z_data_in, c = 'b', marker = '^', s = fig_size * 20.0, alpha = 0.5)
		ax.scatter3D(x_data_out, y_data_out, z_data_out, c = 'y', marker = '^', s = fig_size * 20.0, alpha = 0.5)
		# 锁定坐标轴
		ax.set_xlim(0, Common.BLOCK_size) 
		ax.set_ylim(0, Common.BLOCK_size) 
		ax.set_zlim(0, Common.BLOCK_size) 
		# 绘制标题
		user = 0 # 使用神赐之脑的生
		for i in range(len(block_list_sorted)):
			if len(block_list_sorted[i].connect) > 0:
				user = i
		plt.title('User: ' + str(user) , size = fig_size * 2, loc = 'left') # 标题

		# 保存图片
		file_name = './result-' + name + '/pic-2/' + s + '.png'
		# plt.show()
		plt.savefig(file_name)
		plt.close()

		# 保存摄像头画面
		if self.arrival_enable:
			# 保存生使用的摄像头画面
			file_name = './result-' + name + '/pic-3/' + s + '.png'
			cv2.imwrite(file_name, self.img_use)
			# 保存用于结果展示的摄像头画面
			ret, frame = self.cap_show.read() # 480, 640
			self.img_show = frame
			file_name = './result-' + name + '/pic-4/' + s + '.png'
			cv2.imwrite(file_name, frame)

		# 绘制刻印调用频率图
		scar_font_size = fig_size * 2
		scar_fig_size = (fig_size * 1.0, fig_size * 1.0)
		fig = plt.figure(figsize = scar_fig_size)
		ax = plt.axes()
		# 绘制热力图（只绘制通用块可能匹配到的刻印调用频率）
		data = self.scar_active.transpose().tolist()
		data.append([0.0] * len(self.scar))
		plt.xticks(fontsize = scar_font_size)
		plt.yticks(fontsize = scar_font_size)
		# 绘制层级分隔线
		level_num = int(self.scar_func_num / self.scar_func_type_num)
		for i in range(level_num + 1):
			y_place = i * self.scar_func_type_num - 0.5
			plt.plot([-0.5, len(data[0])], [y_place, y_place], color = 'k', linewidth = fig_size * 0.1)
		plt.title('Scar Rate' , size = fig_size * 2, loc = 'left') # 标题
		im = ax.imshow(data, cmap = plt.cm.RdYlGn) 
		# 保存图片
		file_name = './result-' + name + '/pic-5/' + s + '.png'
		plt.savefig(file_name)
		plt.close()

		# 绘制各刻印到刻印中心距离图
		fig = plt.figure(figsize = scar_fig_size)
		ax = plt.axes()
		# 绘制热力图（只绘制通用块可能匹配到的刻印）
		scar = self.scar
		scar_mid = [] # 刻印中心
		for i in range(len(scar)):
			scar_mid.append(np.mean(scar[i], axis = 0))
		data = [[0.0] * len(scar[0]) + [1.0] ] # 各刻印到刻印中心距离
		for i in range(1, len(scar)):
			one_data = []
			for j in range(len(scar[i])):
				one_data.append(np.mean(np.square(scar[i][j] - scar_mid[i])))
			one_data.append(1.0)
			max_one_data = np.max(one_data)
			if max_one_data == 0:
				max_one_data = np.array(1.0)
			one_data = one_data / max_one_data
			data.append(one_data)
		data = np.array(data).transpose().tolist()
		plt.xticks(fontsize = scar_font_size)
		plt.yticks(fontsize = scar_font_size)
		# 绘制层级分隔线
		level_num = int(self.scar_func_num / self.scar_func_type_num)
		for i in range(level_num + 1):
			y_place = i * self.scar_func_type_num - 0.5
			plt.plot([-0.5, len(data[0])], [y_place, y_place], color = 'k', linewidth = fig_size * 0.1)
		plt.title('Scar Distance', size = fig_size * 2, loc = 'left') # 标题
		im = ax.imshow(data, cmap = plt.cm.RdYlGn) 
		# 保存图片
		file_name = './result-' + name + '/pic-6/' + s + '.png'
		plt.savefig(file_name)
		plt.close()

		# 绘制获得神赐之脑生的素
		fig = plt.figure(figsize = (fig_size * 2.0, fig_size * 0.3))
		ax = plt.axes()
		# 绘制热力图
		data = [] # 8行 64列，把高横向平铺
		grid = self.brain_user.grid
		for i in range(Common.BLOCK_size):
			one_data = []
			for j in range(Common.BLOCK_size):
				for k in range(Common.BLOCK_size):
					index = i * pow(Common.BLOCK_size, 1) + k + j * pow(Common.BLOCK_size, 2)
					one_data.append(grid[index][1])
			# 增加参考值
			if i == 0 or i == 1:
				one_data.append(-1.0)
			elif i == Common.BLOCK_size - 1 or i == Common.BLOCK_size - 2:
				one_data.append(1.0)
			else:
				one_data.append(0.0)
			data.append(one_data)
		plt.xticks(fontsize = scar_font_size)
		plt.yticks(fontsize = scar_font_size)
		# 绘制层级分隔线
		for i in range(1, Common.BLOCK_size + 1):
			x_place = i * Common.BLOCK_size - 0.5
			plt.plot([x_place, x_place], [-0.5, Common.BLOCK_size - 0.5], color = 'k', linewidth = fig_size * 0.1)
		plt.title('Ether Value', size = fig_size * 2, loc = 'left') # 标题
		im = ax.imshow(data, cmap = plt.cm.RdYlGn) 
		plt.text(pow(Common.BLOCK_size, 2) + 2, Common.BLOCK_size, str(user), va = 'bottom', ha = 'right', size = fig_size * 4) #绘制块标记
		ax.yaxis.set_major_locator(plt.NullLocator()) # 同时隐藏刻度和坐标轴标签
		ax.xaxis.set_major_locator(plt.NullLocator())
		# 绘制统计神赐之脑内的数据流向
		for i in range(len(self.grid_io_log)): # [[块, 类型, 起点坐标, 终点坐标], ...]
			if self.grid_io_log[i][0] != self.brain_user:
				continue
			x = [self.grid_io_log[i][2][0] + self.grid_io_log[i][2][2] * Common.BLOCK_size, \
			     self.grid_io_log[i][3][0] + self.grid_io_log[i][3][2] * Common.BLOCK_size]
			y = [self.grid_io_log[i][2][1], self.grid_io_log[i][3][1]]
			if self.grid_io_log[i][1] == 1: # 1、更改指定息
				ax.plot(x, y, color = 'c', linewidth = fig_size * 0.2) # m: 品红, c: 青
				ax.scatter(x[1], y[1], color = 'c', marker = 'h', s = fig_size * 15.0, alpha = 0.5)
			if self.grid_io_log[i][1] == 2: # 2、更改指定素
				ax.plot(x, y, color = 'm', linewidth = fig_size * 0.2)
				ax.scatter(x[1], y[1], color = 'm', marker = 'h', s = fig_size * 15.0, alpha = 0.5)
			if self.grid_io_log[i][1] == 5: # 5、随机化指定息
				ax.scatter(x[0], y[0], color = 'c', marker = 'x', s = fig_size * 15.0)
			if self.grid_io_log[i][1] == 6: # 6、随机化指定素
				ax.scatter(x[0], y[0], color = 'm', marker = 'x', s = fig_size * 15.0)
		# 绘制虚空连接点位
		x_data_in = []
		y_data_in = []
		z_data_in = []
		x_data_out = []
		y_data_out = []
		z_data_out = []
		block = self.brain_user
		for i in range(len(block.connect)):
			t = block.connect[i][0] # 出
			x = t % block.size
			t = int(t / block.size)
			y = t % block.size
			z = int(t / block.size)
			x_data_out.append(x + z * Common.BLOCK_size)
			y_data_out.append(y)
		front_brain = self.brain_list[0]
		for i in range(len(front_brain.connect)):
			if front_brain.connect[i][1] == block:
				t = front_brain.connect[i][2] # 入
				x = t % block.size
				t = int(t / block.size)
				y = t % block.size
				z = int(t / block.size)
				x_data_in.append(x + z * Common.BLOCK_size)
				y_data_in.append(y)
		ax.scatter(x_data_in, y_data_in, c = 'b', marker = '^', s = fig_size * 8.0, alpha = 0.5)
		ax.scatter(x_data_out, y_data_out, c = 'y', marker = '^', s = fig_size * 8.0, alpha = 0.5)
		# 保存图片
		file_name = './result-' + name + '/pic-7/' + s + '.png'
		plt.savefig(file_name)
		plt.close()

		# 绘制回路
		fig = plt.figure(figsize = (fig_size * 0.55, fig_size * 0.55))
		ax = plt.axes(projection='3d')
		keys = list(self.cycle.keys())
		for i in range(len(keys)):
			index = keys[i]
			if self.time - self.cycle[index] > self.cycle_span: # 如果在持续时间以外
				self.cycle.pop(index) # 删除该环
				continue
			# 绘制回路
			max_size = self.brain_user.max_size
			place = int(index / max_size)
			vector = index % max_size
			# 将向量拆分到各维度
			limit = self.brain_user.size
			x = [place % limit + 0.5, vector % limit + 0.5]
			place = int(place / limit)
			vector = int(vector / limit)
			y = [place % limit + 0.5, vector % limit + 0.5]
			place = int(place / limit)
			vector = int(vector / limit)
			z = [place % limit + 0.5, vector % limit + 0.5]
			# 根据据今时间更改回路粗细
			line_width = (self.cycle_span - (self.time - self.cycle[index])) * fig_size * 0.02
			# 根据据今时间更改颜色
			c = 'r' # 红色
			if self.time - self.cycle[index] > self.cycle_span * 0.5: # 较为久远
				c = 'b' # 蓝色
			ax.plot3D(x, y, z, color = c, linewidth = line_width)
			ax.scatter3D(x[1], y[1], z[1], color = 'k', s = fig_size * 10.0, alpha = 0.5)
		# 锁定坐标轴
		ax.set_xlim(0, Common.BLOCK_size) 
		ax.set_ylim(0, Common.BLOCK_size) 
		ax.set_zlim(0, Common.BLOCK_size) 
		# 绘制标题
		plt.title('Cycle, Block: ' + str(user) , size = fig_size * 2, loc = 'left') # 标题
		# 保存图片
		file_name = './result-' + name + '/pic-8/' + s + '.png'
		# plt.show()
		plt.savefig(file_name)
		plt.close()

		# 绘制路径出现次数
		fig = plt.figure(figsize = (fig_size * 0.55, fig_size * 0.55))
		ax = plt.axes()
		path_num_list = []
		keys = list(self.path_num.keys())
		for i in range(len(keys)):
			index = keys[i]
			path_num_list.append(self.path_num[index])
		# 按出现次数排序
		path_num_list = sorted(path_num_list, key = lambda x: x[0], reverse = True)
		y = [] # 出现次数
		the_place = [0] * 5 # 前5位位置
		for i in range(len(path_num_list)):
			y.append(path_num_list[i][0])
			if path_num_list[i][1] < len(the_place): # 找到位置
				the_place[path_num_list[i][1]] = i
		max_y = 0
		if len(y) > 0:
			max_y = max(y)
		plt.plot(y, color = 'k', linewidth = fig_size * 0.3)
		for i in range(len(the_place)):
			c = plt.cm.RdYlGn(float(i) / len(the_place))
			plt.plot([the_place[i], the_place[i]], [max_y * 0.5, 0], color = c, linewidth = fig_size * 0.1, alpha = 0.5)
		# 绘制标题
		plt.title('Path Num, Block: ' + str(user) , size = fig_size * 2, loc = 'left') # 标题
		# # 设置坐标轴字体大小
		# plt.xticks(fontsize = scar_font_size)
		# plt.yticks(fontsize = scar_font_size)
		# 保存图片
		file_name = './result-' + name + '/pic-9/' + s + '.png'
		plt.savefig(file_name)
		plt.close()

		# 写日志
		file_name = './result-' + name + '/log-1/' + s + '.txt'
		result_file = open(file_name, "w")
		result_file.write('\n')
		# 记录魂
		result_file.write('\n')
		result_file.write('Soul Num: ' + str(len(self.soul_list)) + '\n')
		result_file.write('\n')
		for i in range(len(self.soul_list)):
			result_file.write('Num: ' + str(i) + ', Score: ' + str(self.soul_list[i].score) + '\n')
		result_file.write('\n')
		result_file.close()

